package com.runa.monitor.platinterface.netservice.handler;

import com.runa.protocol.analysis.DataAnalysis;
import com.runa.protocol.util.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author zhuj
 */
public class ProtocolDecoder$ extends ByteToMessageDecoder {

    private static final Logger logger = LoggerFactory.getLogger(ProtocolDecoder$.class);

    private DataAnalysis analysis;

    public ProtocolDecoder$(DataAnalysis analysis) {
        this.analysis = analysis;
    }

    private ThreadLocal<byte[]> bufferLocal = new ThreadLocal<>();

    /**
     * 剩余可读
     */
    private ByteBuf remain = Unpooled.buffer();

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        int canRead;
        byte[] bs;
        if (remain.readableBytes() == 0) {
            canRead = in.readableBytes();
            bs = takeLocalBuffer(canRead);
            in.readBytes(bs, 0, canRead);
        } else {
            int remainRead = remain.readableBytes();
            canRead = remainRead + in.readableBytes();
            bs = takeLocalBuffer(canRead);
            remain.readBytes(bs, 0, remainRead);
            in.readBytes(bs, remainRead, in.readableBytes());
        }
        try {
            int status = analysis.fill(bs, canRead,"");
            if (status == 0) {
                if (analysis.gain() != null) {
                    out.add(analysis.gain());
                }
            } else if (status < 0) {
                remain.writeBytes(bs, 0, canRead);
                logger.info("字节流不够 —— {}", remain.readableBytes());
            } else {
                if (analysis.gain() != null) {
                    out.add(analysis.gain());
                }
                remain.writeBytes(bs, canRead-status, status);
            }
        } catch (Exception e) {
            logger.error("ProtocolDecode: ", e);
        } finally {
            logger.info(" Decode: {}", ByteUtil.byteToHexString(bs, 0, canRead));
        }
    }

    private static final int BufferSize = 2048;

    private byte[] takeLocalBuffer(int read) {
        if (bufferLocal.get() == null) {
            bufferLocal.set(new byte[BufferSize]);
        }
        if (read > BufferSize) {
            bufferLocal.set(new byte[read]);
        }
        return bufferLocal.get();
    }
}
